<!--
 * @Author: dazy dazy916@126.com
 * @Date: 2025-09-18 11:37:38
 * @LastEditors: dazy dazy916@126.com
 * @LastEditTime: 2025-09-22 17:58:23
 * @FilePath: \H5\src\pages\student\index.vue
 * @Description: 长按拾取文字功能实现（支持拖动选择，类似微信）
-->
<script setup>
import { reactive, ref, onMounted, getCurrentInstance, onUnmounted, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { showFailToast, showToast } from "vant";
import MainContent from '@/components/mainContent.vue'

const {
    proxy: { $http },
} = getCurrentInstance();
const route = useRoute();
const router = useRouter();

const dataVal = reactive({
    textList: [],
    tabsList: ['第一部分', '第二部分', '第三部分'],
    contentList: [
        '<p>路过一片荆棘丛时，陶陶遇到了蜘蛛。得知她要去参加狮王的婚礼，蜘蛛哈哈大笑，巨大的蜘蛛网被笑声震得剧烈地颤动起来。</p><p>“婚礼两周后就要举行了，你可是慢得出奇呀，怎么可能赶得上呢?”陶陶看了看自己的腿--它们虽然短小，却很结实。她满怀信心地说:“我会准时赶到那里的。”</p><p>蜘蛛充满同情地劝她:“陶陶，我的腿不但比你的灵巧，还多一倍呢，连我都觉得路途太遥远，你还是清醒点儿，赶紧回家吧!”“很遗憾，我不能这样，我的决定是不可改变的。”陶陶友好地回答，又哼哧哼哧地开始赶路了。 </p>',
        '<p>越过种种障碍，穿过树林和沙地，陶陶日夜不停地赶路。</p><p>有一天，陶陶经过一个池塘，她想停下来喝口水。在一片常春藤的叶子上，一只蜗牛正瞪着双眼打量着她。陶陶客气地跟蜗牛打听去狮王二十八世的宫殿怎么走。</p><p>蜗牛想了好一会儿，才把自己那迷迷糊糊的思绪理清楚。他难过地告诉陶陶:“太糟了!你完全走反了方向。</p><p> “非常感谢你给我指路!”说完，陶陶慢慢掉头往回走。</p><p>“可是，后天就要举行婚礼了呀!”蜗牛几乎带着哭腔说。</p><p>只要一步一步坚持走，我会准时赶到的。”陶陶说。</p>',
        '<p>越过种种障碍，穿过树林和沙地，陶陶日夜不停地赶路。</p><p>后来，她遇到了正躺在石头上打盹儿的壁虎。得知陶陶的来意，壁虎居高临下地打量着她说:“作为狮王王宫的高级官员，我正式通知你，婚礼暂时取消了。由于非常突然的原因，狮王二十八世不得不和老虎开战。你可以回家了。”</p><p>......</p>'
    ]
});
const selectedText = ref("");
const showDialog = ref(false);
const isSelecting = ref(false);
const selectionActive = ref(false);
const selectionRange = ref(null);
const activeTab = ref('第一部分');
const showText = ref(0);

// 使用本地存储来保存每个标签页的选择
const STORAGE_KEY = 'submittedSelections';
const submittedSelections = reactive({
    '第一部分': [],
    '第二部分': [],
    '第三部分': []
});

// 从本地存储加载数据
const loadFromStorage = () => {
    try {
        const stored = localStorage.getItem(STORAGE_KEY);
        if (stored) {
            const parsed = JSON.parse(stored);
            Object.keys(parsed).forEach(key => {
                if (submittedSelections[key]) {
                    submittedSelections[key] = parsed[key];
                }
            });
        }
    } catch (e) {
        console.warn('加载本地存储数据失败:', e);
    }
};

// 保存数据到本地存储
const saveToStorage = () => {
    try {
        localStorage.setItem(STORAGE_KEY, JSON.stringify(submittedSelections));
    } catch (e) {
        console.warn('保存到本地存储失败:', e);
    }
};

let longPressTimer = null;
let toolbarElement = null;
let startHandle = null;
let endHandle = null;

// 监听标签页切换
watch(showText, (newVal) => {
    // 取消当前选择
    cancelSelection();

    // 延迟一下确保DOM更新完成
    setTimeout(() => {
        highlightSubmittedSelections();
    }, 100);
});

// 添加滚动事件处理函数
const handleScroll = () => {
    if (startHandle && endHandle && selectionRange.value) {
        positionHandle(startHandle, selectionRange.value, true);
        positionHandle(endHandle, selectionRange.value, false);
        updateToolbarPosition(); // 同时更新工具栏位置
    }
};

// 添加更新工具栏位置的函数
const updateToolbarPosition = () => {
    if (toolbarElement && selectionRange.value) {
        const rangeRect = selectionRange.value.getBoundingClientRect();
        const toolbarWidth = toolbarElement.offsetWidth || 200;
        // toolbarElement.style.left = (rangeRect.right - toolbarWidth / 2) + 'px'
        // toolbarElement.style.top = (rangeRect.bottom + 60) + 'px'
    }
};

// 创建自定义选择控件
const createSelectionHandles = () => {
    removeSelectionHandles();

    const selection = window.getSelection();
    if (!selection.rangeCount) return;

    const range = selection.getRangeAt(0);
    selectionRange.value = range;

    startHandle = document.createElement("div");
    startHandle.className = "selection-handle selection-handle-start";
    startHandle.innerHTML = "‹›";

    endHandle = document.createElement("div");
    endHandle.className = "selection-handle selection-handle-end";
    endHandle.innerHTML = "‹›";

    positionHandle(startHandle, range, true);
    positionHandle(endHandle, range, false);

    document.body.appendChild(startHandle);
    document.body.appendChild(endHandle);

    addDragEvents(startHandle, true);
    addDragEvents(endHandle, false);

    // 添加滚动事件监听
    window.addEventListener("scroll", handleScroll, { passive: true });
};

// 添加获取文本内容实际边界的方法
const getTextContentBounds = () => {
    const textContainer = document.querySelector(".selectable-text");
    if (!textContainer) return null;

    const ranges = [];
    const textNodes = getTextNodes(textContainer);

    // 为每个文本节点创建范围
    textNodes.forEach((node) => {
        try {
            if (node.textContent.trim().length > 0) {
                const range = document.createRange();
                range.setStart(node, 0);
                range.setEnd(node, node.textContent.length);
                ranges.push(range);
            }
        } catch (e) {
            // 忽略错误
        }
    });

    if (ranges.length === 0) return textContainer.getBoundingClientRect();

    // 计算所有范围的边界
    let left = Infinity;
    let top = Infinity;
    let right = -Infinity;
    let bottom = -Infinity;

    ranges.forEach((range) => {
        try {
            const rect = range.getBoundingClientRect();
            left = Math.min(left, rect.left);
            top = Math.min(top, rect.top);
            right = Math.max(right, rect.right);
            bottom = Math.max(bottom, rect.bottom);
        } catch (e) {
            // 忽略错误
        }
    });

    if (
        isFinite(left) &&
        isFinite(top) &&
        isFinite(right) &&
        isFinite(bottom)
    ) {
        return { left, top, right, bottom };
    }

    return textContainer.getBoundingClientRect();
};

// 定位选择手柄
const positionHandle = (handle, range, isStart) => {
    try {
        // 获取范围边界
        const rect = range.getBoundingClientRect();

        // 获取段落边界
        let paragraphBounds = null;
        if (selectionRange.value && selectionRange.value._restrictedParagraph) {
            paragraphBounds =
                selectionRange.value._restrictedParagraph.getBoundingClientRect();
        } else {
            const textContainer = document.querySelector(".selectable-text");
            if (textContainer) {
                paragraphBounds = textContainer.getBoundingClientRect();
            }
        }

        handle.style.position = "absolute";
        handle.style.zIndex = "1000";

        // 优化手柄初始位置计算
        let leftPos, topPos;
        if (isStart) {
            // 起始手柄放在范围的开始位置，稍微向右偏移以确保能选中第一个字符
            leftPos = rect.left + 2;
        } else {
            // 结束手柄放在范围的结束位置，稍微向左偏移
            leftPos = rect.right - 2;
        }
        topPos = rect.bottom + 5;

        // 严格限制在段落范围内
        if (paragraphBounds) {
            const handleRadius = 12;
            leftPos = Math.max(
                paragraphBounds.left + handleRadius,
                Math.min(paragraphBounds.right - handleRadius, leftPos)
            );
            topPos = Math.max(
                paragraphBounds.top,
                Math.min(paragraphBounds.bottom, topPos)
            );
        }

        handle.style.left = leftPos + "px";
        handle.style.top = topPos + "px";

        // 强制重绘以确保位置正确
        handle.offsetHeight;
    } catch (e) {
        console.warn("定位手柄时出错:", e);
    }
};

// 添加拖拽事件
const addDragEvents = (handle, isStartHandle) => {
    let isDragging = false
    let startX, startY
    let paragraphRect = null
    let initialScrollPosition = 0

    // 为每个手柄创建独立的事件处理函数
    const onTouchStart = (e) => {
        // 检查触摸目标是否是工具栏或其子元素
        if (e.target.closest('.custom-selection-toolbar')) {
            // 如果触摸的是工具栏，不处理拖拽
            return
        }

        console.log(`${isStartHandle ? 'Start' : 'End'} handle touch start`)
        e.preventDefault()
        e.stopPropagation()
        isDragging = true
        startX = e.touches[0].clientX
        startY = e.touches[0].clientY

        // 禁止页面滚动
        document.body.style.overflow = 'hidden'
        document.body.style.touchAction = 'none'

        // 保存初始滚动位置
        initialScrollPosition = window.scrollY

        // 获取当前选择范围限制的段落边界
        if (selectionRange.value && selectionRange.value._restrictedParagraph) {
            paragraphRect = selectionRange.value._restrictedParagraph.getBoundingClientRect()
        } else {
            // 降级到文本容器边界
            const textContainer = document.querySelector('.selectable-text')
            if (textContainer) {
                paragraphRect = textContainer.getBoundingClientRect()
            }
        }
    }

    const onTouchMove = (e) => {
        removeSelectionToolbar()
        // 检查触摸目标是否是工具栏或其子元素
        if (e.target.closest('.custom-selection-toolbar')) {
            return
        }

        if (!isDragging) return
        console.log(`${isStartHandle ? 'Start' : 'End'} handle touch move`)
        e.preventDefault()
        e.stopPropagation()

        // 阻止页面滚动
        window.scrollTo(0, initialScrollPosition)

        const currentX = e.touches[0].clientX
        const currentY = e.touches[0].clientY
        const deltaX = currentX - startX
        const deltaY = currentY - startY

        // 计算新手柄位置
        let newX = parseFloat(handle.style.left) + deltaX
        let newY = parseFloat(handle.style.top) + deltaY

        // 使用段落边界进行严格限制
        if (paragraphRect) {
            // 严格限制在段落范围内，考虑手柄大小
            const handleRadius = 12; // 手柄半径
            newX = Math.max(
                paragraphRect.left + handleRadius,
                Math.min(paragraphRect.right - handleRadius, newX)
            )
            newY = Math.max(
                paragraphRect.top - 20,
                Math.min(paragraphRect.bottom + 20, newY)
            )
        }

        // 更新手柄位置
        handle.style.left = newX + 'px'
        handle.style.top = newY + 'px'

        startX = currentX
        startY = currentY

        updateSelectionFromHandle(handle, isStartHandle)
    }

    const onTouchEnd = (e) => {
        // 检查触摸目标是否是工具栏或其子元素
        if (e.target.closest('.custom-selection-toolbar')) {
            return
        }

        console.log(`${isStartHandle ? 'Start' : 'End'} handle touch end`)
        e.preventDefault()
        e.stopPropagation()
        isDragging = false

        // 恢复页面滚动
        document.body.style.overflow = ''
        document.body.style.touchAction = ''

        showSelectionToolbar();
    }

    // 确保手柄已经被添加到DOM中
    const bindEvents = () => {
        // 先移除可能存在的旧事件监听器
        if (isStartHandle && handle._startEvents) {
            const { onTouchStart: oldStart, onTouchMove: oldMove, onTouchEnd: oldEnd } = handle._startEvents
            handle.removeEventListener('touchstart', oldStart)
            handle.removeEventListener('touchmove', oldMove)
            handle.removeEventListener('touchend', oldEnd)
        } else if (!isStartHandle && handle._endEvents) {
            const { onTouchStart: oldStart, onTouchMove: oldMove, onTouchEnd: oldEnd } = handle._endEvents
            handle.removeEventListener('touchstart', oldStart)
            handle.removeEventListener('touchmove', oldMove)
            handle.removeEventListener('touchend', oldEnd)
        }

        // 添加新的事件监听器
        handle.addEventListener('touchstart', onTouchStart, { passive: false })
        handle.addEventListener('touchmove', onTouchMove, { passive: false })
        handle.addEventListener('touchend', onTouchEnd, { passive: false })

        // 保存事件引用
        if (isStartHandle) {
            handle._startEvents = { onTouchStart, onTouchMove, onTouchEnd }
        } else {
            handle._endEvents = { onTouchStart, onTouchMove, onTouchEnd }
        }
    }

    // 使用多种方式确保事件绑定成功
    if (handle.parentNode) {
        // 如果已经添加到DOM中，直接绑定
        bindEvents()
    } else {
        // 等待添加到DOM后再绑定
        const observer = new MutationObserver((mutations, obs) => {
            if (handle.parentNode) {
                bindEvents()
                obs.disconnect()
            }
        })

        observer.observe(document.body, { childList: true, subtree: true })

        // 设置超时防止内存泄漏
        setTimeout(() => {
            observer.disconnect()
            if (handle.parentNode) {
                bindEvents()
            }
        }, 100)
    }
}

// 添加一个更精确的字符位置查找函数
const findPreciseTextPosition = (x, y, isStartHandle) => {
    // 优先在限制的段落内查找
    let targetParagraph = null;
    if (selectionRange.value && selectionRange.value._restrictedParagraph) {
        targetParagraph = selectionRange.value._restrictedParagraph;
    } else {
        targetParagraph = getParagraphAtPosition(x, y);
    }

    if (!targetParagraph) {
        const textContainer = document.querySelector(".selectable-text");
        if (!textContainer) return null;
        targetParagraph = textContainer;
    }

    const textNodes = getTextNodes(targetParagraph);
    if (textNodes.length === 0) return null;

    let closestPosition = null;
    let minDistance = Infinity;

    textNodes.forEach((node) => {
        const text = node.textContent;

        // 检查整个文本节点的范围
        try {
            const nodeRange = document.createRange();
            nodeRange.setStart(node, 0);
            nodeRange.setEnd(node, text.length);
            const nodeRect = nodeRange.getBoundingClientRect();

            // 如果点击位置在节点范围之外，跳过
            if (
                x < nodeRect.left - 20 ||
                x > nodeRect.right + 20 ||
                y < nodeRect.top - 20 ||
                y > nodeRect.bottom + 20
            ) {
                return;
            }
        } catch (e) {
            // 继续处理
        }

        // 逐字符检查
        for (let i = 0; i <= text.length; i++) {
            try {
                const range = document.createRange();
                range.setStart(node, i);
                range.setEnd(node, i);

                const rect = range.getBoundingClientRect();

                // 根据是起始手柄还是结束手柄，调整位置偏好
                let targetX, targetY;
                if (isStartHandle) {
                    // 起始手柄偏向于字符的开始位置
                    targetX =
                        i === 0 ? rect.left : rect.left + rect.width * 0.3;
                    targetY = rect.top + rect.height / 2;
                } else {
                    // 结束手柄偏向于字符的结束位置
                    targetX =
                        i === text.length
                            ? rect.right
                            : rect.left + rect.width * 0.7;
                    targetY = rect.top + rect.height / 2;
                }

                const distance = Math.sqrt(
                    Math.pow(targetX - x, 2) + Math.pow(targetY - y, 2)
                );

                if (distance < minDistance) {
                    minDistance = distance;
                    closestPosition = { node, offset: i };
                }
            } catch (e) {
                // 忽略无法创建范围的位置
            }
        }
    });

    return closestPosition;
};

// 根据手柄位置更新选择
const updateSelectionFromHandle = (handle, isStartHandle) => {
    // 使用手柄中心点稍微偏移的位置来计算字符位置
    const handleRect = handle.getBoundingClientRect();
    const x = handleRect.left + handleRect.width / 2;
    const y = handleRect.top + handleRect.height / 3;

    if (!selectionRange.value) return;

    // 查找最接近手柄位置的字符
    const newPosition = findClosestTextPosition(x, y);

    if (newPosition) {
        const selection = window.getSelection();
        selection.removeAllRanges();

        try {
            if (isStartHandle) {
                // 更新起始位置
                const endContainer = selectionRange.value.endContainer;
                const endOffset = selectionRange.value.endOffset;

                // 确保起始位置不超出结束位置
                if (
                    comparePositions(
                        newPosition.node,
                        newPosition.offset,
                        endContainer,
                        endOffset
                    ) <= 0
                ) {
                    selectionRange.value.setStart(
                        newPosition.node,
                        newPosition.offset
                    );
                    selectionRange.value.setEnd(endContainer, endOffset);
                }
            } else {
                // 更新结束位置
                const startContainer = selectionRange.value.startContainer;
                const startOffset = selectionRange.value.startOffset;

                // 确保结束位置不小于起始位置
                if (
                    comparePositions(
                        startContainer,
                        startOffset,
                        newPosition.node,
                        newPosition.offset
                    ) <= 0
                ) {
                    selectionRange.value.setStart(startContainer, startOffset);
                    selectionRange.value.setEnd(
                        newPosition.node,
                        newPosition.offset
                    );
                }
            }

            selection.addRange(selectionRange.value);
            updateSelectedText();
            updateToolbarPosition();

            if (toolbarElement && toolbarElement.parentNode === endHandle) {
                setTimeout(() => {
                    adjustToolbarPosition();
                }, 0);
            }
        } catch (err) {
            console.warn("更新选择范围时出错:", err);
        }
    }
};

// 查找最接近指定坐标的文本位置
const findClosestTextPosition = (x, y) => {
    // 优先在限制的段落内查找
    let targetParagraph = null;
    if (selectionRange.value && selectionRange.value._restrictedParagraph) {
        targetParagraph = selectionRange.value._restrictedParagraph;
    } else {
        // 降级到通过坐标查找段落
        targetParagraph = getParagraphAtPosition(x, y);
    }

    if (!targetParagraph) {
        const textContainer = document.querySelector(".selectable-text");
        if (!textContainer) return null;
        targetParagraph = textContainer;
    }

    const textNodes = getTextNodes(targetParagraph);
    if (textNodes.length === 0) return null;

    let closestPosition = null;
    let minDistance = Infinity;

    textNodes.forEach((node) => {
        const text = node.textContent;

        // 逐字符检查
        for (let i = 0; i <= text.length; i++) {
            try {
                const range = document.createRange();
                range.setStart(node, i);
                range.setEnd(node, i);

                const rect = range.getBoundingClientRect();

                // 计算手柄中心点到字符位置的距离
                // 对于起始位置，我们偏向于选择字符的开始位置
                // 对于结束位置，我们偏向于选择字符的结束位置
                let targetX = rect.left + rect.width / 2;
                let targetY = rect.top + rect.height / 2;

                // 调整X坐标计算，使边界字符更容易选中
                if (i === 0) {
                    // 第一个字符，稍微向左偏移以便更容易选中
                    targetX = rect.left + 10 + rect.width * 0.7;
                } else if (i === text.length) {
                    // 最后一个字符，稍微向右偏移
                    targetX = rect.right - rect.width * 0.3;
                }

                const distance = Math.sqrt(
                    Math.pow(targetX - x, 2) + Math.pow(targetY - y, 2)
                );

                if (distance < minDistance) {
                    minDistance = distance;
                    closestPosition = { node, offset: i };
                }
            } catch (e) {
                // 忽略无法创建范围的位置
            }
        }
    });

    return closestPosition;
};

// 比较两个文本位置的先后顺序
const comparePositions = (nodeA, offsetA, nodeB, offsetB) => {
    if (nodeA === nodeB) {
        return offsetA - offsetB;
    }

    // 创建范围来比较节点顺序
    const range = document.createRange();
    range.setStart(nodeA, offsetA);
    range.setEnd(nodeB, offsetB);

    if (range.collapsed) {
        // 如果范围是折叠的，说明位置相同
        return 0;
    }

    // 检查范围的方向
    const compare = range.compareBoundaryPoints(Range.START_TO_END, range);
    return compare === 0 ? -1 : 1;
};

// 添加调整工具栏位置的函数
const adjustToolbarPosition = () => {
    if (toolbarElement && toolbarElement.parentNode === endHandle) {
        const toolbarRect = toolbarElement.getBoundingClientRect();
        const viewportWidth = window.innerWidth;

        // 重置位置
        toolbarElement.style.left = "50%";
        toolbarElement.style.transform = "translateX(-50%)";

        // 检查边界并调整
        setTimeout(() => {
            const newToolbarRect = toolbarElement.getBoundingClientRect();

            if (newToolbarRect.right > viewportWidth) {
                const overflow = newToolbarRect.right - viewportWidth;
                toolbarElement.style.left = `calc(50% - ${overflow}px)`;
                toolbarElement.style.transform = "none";
            } else if (newToolbarRect.left < 0) {
                const overflow = Math.abs(newToolbarRect.left);
                toolbarElement.style.left = `calc(50% + ${overflow}px)`;
                toolbarElement.style.transform = "none";
            }
        }, 0);
    }
};

// 移除选择手柄
const removeSelectionHandles = () => {
    // 移除工具栏（如果它是 endHandle 的子元素）
    if (toolbarElement && toolbarElement.parentNode === endHandle) {
        toolbarElement.remove();
        toolbarElement = null;
    }

    if (startHandle) {
        // 移除事件监听器
        if (startHandle._startEvents) {
            const { onTouchStart, onTouchMove, onTouchEnd } =
                startHandle._startEvents;
            startHandle.removeEventListener("touchstart", onTouchStart);
            startHandle.removeEventListener("touchmove", onTouchMove);
            startHandle.removeEventListener("touchend", onTouchEnd);
        }
        startHandle.remove();
        startHandle = null;
    }

    if (endHandle) {
        // 移除事件监听器
        if (endHandle._endEvents) {
            const { onTouchStart, onTouchMove, onTouchEnd } =
                endHandle._endEvents;
            endHandle.removeEventListener("touchstart", onTouchStart);
            endHandle.removeEventListener("touchmove", onTouchMove);
            endHandle.removeEventListener("touchend", onTouchEnd);
        }
        endHandle.remove();
        endHandle = null;
    }

    // 移除滚动事件监听
    window.removeEventListener("scroll", handleScroll);

    // 如果工具栏仍然存在（未被清理），则移除它
    if (toolbarElement) {
        toolbarElement.remove();
        toolbarElement = null;
    }
};

// 更新选中的文本
const updateSelectedText = () => {
    const selection = window.getSelection();
    const text = selection.toString().trim();
    selectedText.value = text;
};

// 长按事件处理
const onLongPress = (e) => {
    clearTimeout(longPressTimer)
    longPressTimer = setTimeout(() => {
        e.preventDefault()
        isSelecting.value = true
        selectionActive.value = true

        // 禁止页面滚动
        document.body.style.overflow = 'hidden'

        const touch = e.touches[0]
        const x = touch.clientX
        const y = touch.clientY

        // 使用新的基于段落限制的选择方法
        selectTextByPositionWithinParagraph(x, y)
    }, 500)
};

// 新增：根据位置选择文本，限制在同一段落内
const selectTextByPositionWithinParagraph = (x, y) => {
    const textContainer = document.querySelector(".selectable-text");
    if (!textContainer) return;

    // 获取点击位置所在的段落
    const targetParagraph = getParagraphAtPosition(x, y);
    if (!targetParagraph) return;

    // 获取该段落内的所有文本节点
    const textNodes = getTextNodes(targetParagraph);
    if (textNodes.length === 0) return;

    let closestNode = null;
    let closestOffset = 0;
    let minDistance = Infinity;

    // 查找最接近点击位置的文本节点和偏移量
    textNodes.forEach((node) => {
        const range = document.createRange();
        const text = node.textContent;

        for (let i = 0; i <= text.length; i++) {
            range.setStart(node, i);
            range.setEnd(node, i);

            const rect = range.getBoundingClientRect();
            const distance = Math.sqrt(
                Math.pow(rect.left + rect.width / 2 - x, 2) +
                Math.pow(rect.top + rect.height / 2 - y, 2)
            );

            if (distance < minDistance) {
                minDistance = distance;
                closestNode = node;
                closestOffset = i;
            }
        }
    });

    if (closestNode) {
        // 创建初始选择范围（选择一个字符）
        const selection = window.getSelection();
        selection.removeAllRanges();

        const range = document.createRange();
        const textLength = closestNode.textContent.length;

        // 确保不超出文本范围
        const startOffset = Math.max(
            0,
            Math.min(closestOffset, textLength - 1)
        );
        const endOffset = Math.min(startOffset + 1, textLength);

        range.setStart(closestNode, startOffset);
        range.setEnd(closestNode, endOffset);

        selection.addRange(range);
        selectionRange.value = range;

        // 保存段落限制信息
        selectionRange.value._restrictedParagraph = targetParagraph;

        updateSelectedText();
        createSelectionHandles();
    }

    isSelecting.value = false;
};

// 获取点击位置所在的段落
const getParagraphAtPosition = (x, y) => {
    const textContainer = document.querySelector(".selectable-text");
    if (!textContainer) return null;

    const paragraphs = textContainer.querySelectorAll("p");
    for (let paragraph of paragraphs) {
        const rect = paragraph.getBoundingClientRect();
        if (
            x >= rect.left &&
            x <= rect.right &&
            y >= rect.top &&
            y <= rect.bottom
        ) {
            return paragraph;
        }
    }

    // 如果没有找到精确匹配，返回包含坐标的第一个段落
    for (let paragraph of paragraphs) {
        const rect = paragraph.getBoundingClientRect();
        if (y >= rect.top && y <= rect.bottom) {
            return paragraph;
        }
    }

    // 如果还是没有找到，返回第一个段落
    return paragraphs.length > 0 ? paragraphs[0] : null;
};

// 获取元素内所有文本节点
const getTextNodes = (element) => {
    const textNodes = [];
    const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, {
        acceptNode: (node) => {
            // 过滤掉只有空白字符的节点
            if (node.textContent.trim()) {
                return NodeFilter.FILTER_ACCEPT;
            }
            return NodeFilter.FILTER_REJECT;
        },
    });

    let node;
    while ((node = walker.nextNode())) {
        textNodes.push(node);
    }

    return textNodes;
};

// 显示选择工具栏
const showSelectionToolbar = () => {
    removeSelectionToolbar();

    toolbarElement = document.createElement("div");
    toolbarElement.className = "custom-selection-toolbar";
    toolbarElement.innerHTML = `
    <div style="display: flex; gap: 10px; padding: 8px; background: white; border-radius: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.15);">
      <button class="toolbar-btn cancel-btn" >取消</button>
      <button class="toolbar-btn submit-btn" >提交</button>
    </div>
  `;

    // 将工具栏作为 endHandle 的子元素添加
    if (endHandle) {
        endHandle.appendChild(toolbarElement);

        // 设置相对定位
        toolbarElement.style.position = "absolute";
        toolbarElement.style.zIndex = "1009";
        toolbarElement.style.bottom = "60px";
        toolbarElement.style.left = "50%";
        toolbarElement.style.transform = "translateX(-50%)";

        // 为工具栏添加事件处理，防止拖拽事件传播
        toolbarElement.addEventListener("touchstart", (e) => {
            e.stopPropagation(); // 阻止事件冒泡到手柄
        });

        toolbarElement.addEventListener("touchmove", (e) => {
            e.stopPropagation(); // 阻止事件冒泡到手柄
        });

        toolbarElement.addEventListener("touchend", (e) => {
            e.stopPropagation(); // 阻止事件冒泡到手柄
        });
    } else {
        // 如果没有末端手柄，回退到原来的方式
        document.body.appendChild(toolbarElement);
        toolbarElement.style.position = "absolute";
        toolbarElement.style.zIndex = "1009";

        if (selectionRange.value) {
            const rangeRect = selectionRange.value.getBoundingClientRect();
            const toolbarWidth = toolbarElement.offsetWidth || 200;
            toolbarElement.style.left =
                rangeRect.right - toolbarWidth / 2 + "px";
            toolbarElement.style.top = rangeRect.bottom + 10 + "px";
        }
    }

    // 为按钮添加独立的点击事件处理
    const cancelBtn = toolbarElement.querySelector(".cancel-btn");
    const submitBtn = toolbarElement.querySelector(".submit-btn");

    // 确保按钮可以被点击
    cancelBtn.addEventListener("click", (e) => {
        e.stopPropagation(); // 阻止事件冒泡
        cancelSelection();
    });

    submitBtn.addEventListener("click", (e) => {
        e.stopPropagation(); // 阻止事件冒泡
        submitSelection();
    });

    // 为按钮添加触摸事件处理，防止触发拖拽
    cancelBtn.addEventListener("touchstart", (e) => {
        e.stopPropagation();
    });

    cancelBtn.addEventListener("touchend", (e) => {
        e.stopPropagation();
        cancelSelection();
    });

    submitBtn.addEventListener("touchstart", (e) => {
        e.stopPropagation();
    });

    submitBtn.addEventListener("touchend", (e) => {
        e.stopPropagation();
        submitSelection();
    });
};

// 移除选择工具栏
const removeSelectionToolbar = () => {
    if (toolbarElement) {
        toolbarElement.remove();
        toolbarElement = null;
    }
};

// 取消选择
const cancelSelection = () => {
    selectedText.value = null
    selectionActive.value = false
    removeSelectionHandles()
    removeSelectionToolbar()
    const selection = window.getSelection()
    if (selection) selection.removeAllRanges()

    // 恢复页面滚动
    document.body.style.overflow = ''
    document.body.style.touchAction = ''

    // showToast('已取消选择')
};

// 添加一个状态来跟踪哪些标签页已经通过 submitFull 提交
const submittedTabs = reactive({
    '第一部分': false,
    '第二部分': false,
    '第三部分': false
});
// 完整提交
const submitFull = async () => {
    // 收集所有标签页的文本
    const allTexts = [];
    Object.values(submittedSelections).forEach(selections => {
        selections.forEach(selection => {
            allTexts.push(selection.text);
        });
    });

    if (allTexts.length === 0) {
        showToast("请先选择文本");
        return;
    }

    try {
        const response = await $http.post("/student/markSave", {
            student: sessionStorage.getItem("studentNumber"),
            paragraph: (showText.value + 1).toString(),
            markContent: dataVal.textList,
        });
        console.info(response)
        if (response.code === 200) {
            showToast("提交成功");
            saveToStorage();

            // 标记当前标签页为已提交
            submittedTabs[dataVal.tabsList[showText.value]] = true;

            // 清空当前标签页的暂存选择
            // submittedSelections[dataVal.tabsList[showText.value]] = [];
            dataVal.textList = [];

            // 清除高亮
            // clearHighlights();
        } else {
            showToast("提交失败: " + response.data.message);
        }
    } catch (error) {
        console.error("提交出错:", error);
        showToast("提交出错，请重试");
    }
};

// 提交选择
const submitSelection = async () => {
    if (!selectedText.value) {
        showToast("请先选择文本");
        return;
    } else {
        // 获取当前选择范围
        const selection = window.getSelection();
        if (selection.rangeCount > 0) {
            const range = selection.getRangeAt(0);
            const currentTab = dataVal.tabsList[showText.value];

            // 获取选择范围的上下文信息
            const startContainerText = range.startContainer.textContent;
            const endContainerText = range.endContainer.textContent;
            const selectedTextContent = selectedText.value;

            // 存储选择信息（不包含DOM引用）
            submittedSelections[currentTab].push({
                text: selectedText.value,
                startText: startContainerText,
                startOffset: range.startOffset,
                endText: endContainerText,
                endOffset: range.endOffset,
                id: Date.now(),
                // 存储段落索引信息
                paragraphIndex: getParagraphIndex(range.startContainer),
                fullText: document.querySelector(".selectable-text").innerText
            });

            dataVal.textList.push(selectedText.value);

            // 保存到本地存储
            // saveToStorage();

            // 更新UI显示下划线
            highlightSubmittedSelections();

            console.log("mounted", submittedSelections[dataVal.tabsList[showText.value]].length);
        }
        cancelSelection();
    }
};
// 获取段落索引
const getParagraphIndex = (node) => {
    const paragraphs = document.querySelectorAll(".selectable-text p");
    for (let i = 0; i < paragraphs.length; i++) {
        if (paragraphs[i].contains(node)) {
            return i;
        }
    }
    return -1;
};
// 高亮已提交的文本选择
const highlightSubmittedSelections = () => {
    // 先清除所有现有的高亮
    // clearHighlights();

    const currentTab = dataVal.tabsList[showText.value];
    const selections = submittedSelections[currentTab] || [];

    if (selections.length === 0) return;

    const textContainer = document.querySelector(".selectable-text");
    if (!textContainer) return;

    // 获取所有文本节点
    const textNodes = getTextNodes(textContainer);
    if (textNodes.length === 0) return;

    selections.forEach(selection => {
        try {
            // 在新的DOM中查找匹配的文本位置
            let foundStart = false;
            let foundEnd = false;
            let startNode = null, endNode = null;
            let startOffset = 0, endOffset = 0;

            // 遍历所有文本节点查找匹配的文本
            for (const node of textNodes) {
                const nodeText = node.textContent;

                // 查找起始位置
                if (!foundStart && nodeText.includes(selection.startText)) {
                    const startIndex = nodeText.indexOf(selection.startText);
                    if (startIndex + selection.startOffset <= nodeText.length) {
                        startNode = node;
                        startOffset = startIndex + selection.startOffset;
                        foundStart = true;
                    }
                }

                // 查找结束位置
                if (!foundEnd && nodeText.includes(selection.endText)) {
                    const endIndex = nodeText.indexOf(selection.endText);
                    if (endIndex + selection.endOffset <= nodeText.length) {
                        endNode = node;
                        endOffset = endIndex + selection.endOffset;
                        foundEnd = true;
                    }
                }

                if (foundStart && foundEnd) break;
            }

            // 如果找到了匹配的位置，创建高亮
            if (foundStart && foundEnd && startNode && endNode) {
                const range = document.createRange();
                range.setStart(startNode, startOffset);
                range.setEnd(endNode, endOffset);

                // 检查范围文本是否匹配
                if (range.toString().trim() === selection.text.trim()) {
                    // 创建高亮元素
                    const highlight = document.createElement('span');
                    highlight.className = 'text-highlight';
                    highlight.dataset.id = selection.id;
                    highlight.style.textDecoration = 'underline';
                    highlight.style.textDecorationColor = '#E95294';
                    highlight.style.textDecorationThickness = '2px';

                    // 用高亮元素包裹文本
                    range.surroundContents(highlight);
                }
            }
        } catch (e) {
            console.warn('无法高亮文本:', e);
            // 如果高亮失败，使用备选方案：简单文本匹配
            highlightByTextContent(selection);
        }
    });
};

// 清除所有高亮
const clearHighlights = () => {
    const highlights = document.querySelectorAll('.text-highlight');
    highlights.forEach(highlight => {
        const parent = highlight.parentNode;
        parent.replaceChild(document.createTextNode(highlight.textContent), highlight);
        parent.normalize(); // 合并相邻的文本节点
    });
};

// 点击其他地方取消选择
const handleDocumentClick = (e) => {
    if (
        selectionActive.value &&
        !e.target.closest(".selectable-text") &&
        !e.target.closest(".selection-handle") &&
        !e.target.closest(".custom-selection-toolbar")
    ) {
        cancelSelection();
    }
};

// 点击选择区域外部时取消选择
const handleSelectionClick = (e) => {
    if (!e.target.closest(".selectable-text")) {
        // cancelSelection()
    }
};
// 切换三部分
const changeTab = (tab, idx) => {
    // 获取当前标签页的索引
    const currentIndex = dataVal.tabsList.findIndex(t => t === activeTab.value);
    const targetIndex = idx;

    // 如果是向前切换
    if (targetIndex > currentIndex) {
        // 检查所有前面的标签页是否都已经提交
        for (let i = 0; i < targetIndex; i++) {
            const tabName = dataVal.tabsList[i];
            if (!submittedTabs[tabName]) {
                showFailToast({
                    message: `请先完成${tabName}的文本选择并点击提交按钮！`,
                    duration: 3000
                });
                return; // 阻止切换
            }
        }
    }

    // 如果是向后切换或所有前面标签页都已提交，允许切换
    activeTab.value = tab;
    showText.value = idx;

    // 使用nextTick确保DOM更新完成后再应用高亮
    setTimeout(() => {
        highlightSubmittedSelections();
    }, 50);
};

onMounted(() => {
    document.addEventListener("click", handleDocumentClick);
    document.addEventListener("touchstart", handleSelectionClick);
});

onUnmounted(() => {
    clearTimeout(longPressTimer);
    document.removeEventListener("click", handleDocumentClick);
    document.removeEventListener("touchstart", handleSelectionClick);
    cancelSelection();
});
</script>

<template>
    <MainContent contentWidth="100%" padding="0">
        <template #content>
            <div class="container d-flex gap-1 flex-1 height100">
                <div class="result-panel width30 borderbox d-flex direction-column align-items-center">
                    <img src="@/assets/img/three.png" alt="教学系统功能展示" class="image-item" loading="lazy" />
                    <van-divider class="divider">三段勾完记得点击下方提交哦</van-divider>

                    <!-- <div class="result-title">已拾取的文本</div>
                    <div class="selected-text width100">
                        <div v-for="(item, index) in dataVal.textList" :key="index" class="selected-item">
                            {{ item }}
                        </div>
                    </div>-->
                    <van-button color="#E95294" block @click.stop="submitFull"
                        :disabled="submittedSelections[dataVal.tabsList[showText]]?.length === 0"
                        class="size-20 submitbtn">提交</van-button>
                </div>
                <div class="content width70 borderbox">
                    <div class="d-flex space-between text-tabs">
                        <div class="tab-item" :class="{ active: activeTab === tabs }" @click="changeTab(tabs, idx)"
                            v-for="(tabs, idx) in dataVal.tabsList">{{ tabs }}</div>
                    </div>
                    <div class="selectable-text d-flex justify-content-start" @touchstart="onLongPress">
                        <template v-for="(textItem, index) in dataVal.contentList">
                            <div v-html="textItem" v-if="showText === index"></div>
                        </template>
                    </div>
                </div>
            </div>
        </template>
    </MainContent>
</template>

<style scoped lang="scss">
.container {
    max-width: 90%;
    overflow-y: auto;
    margin: 0 auto;
    padding: 20px;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
}

header {
    text-align: center;
    margin-bottom: 30px;
}

h1 {
    color: #3a7afe;
    margin-bottom: 10px;
    font-size: 24px;
}

.description {
    color: #666;
    font-size: 16px;
}

.submitbtn {
    margin-top: 40px;
    height: 50px;
    width: 120px;
}

.content {
    border-radius: 12px;
    padding: 10px 20px;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);

    .text-tabs {
        margin: 0 auto;
        box-sizing: border-box;
        width: 540px;
        height: 60px;
        border-radius: 50px;
        background: #E9529426;
        overflow: hidden;

        .tab-item {
            font-family: Alibaba PuHuiTi 2.0;
            font-weight: 400;
            font-style: 55 Regular;
            font-size: 1.625rem;
            line-height: 60px;
            letter-spacing: 0%;
            text-align: center;
            padding: 0 40px;
            cursor: pointer;

            &.active {
                color: #fff;
                background-color: #E95294;
            }
        }
    }
}

.selectable-text {
    margin-top: 30px;
    height: calc(100% - 100px);
    overflow-y: auto;
    -webkit-user-select: text;
    user-select: text;
    div{
        margin-top: -20px;
        font-family: KaiTi;
            font-weight: 400;
            font-size: 1.625rem;
            line-height: 2.625rem;
            text-align: justify;
            text-indent: 2em;
            color: #333;
    }
}

.result-panel {
    height: 100%;
    border-radius: 12px;
    padding: 20px;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);

    .divider {
        font-size: 1rem;
        color: #E95294;
        margin-top: 80px;
    }

    .image-item {
        width: 240px;
    }
}

.result-title {
    font-size: 1.25rem;
    font-weight: 500;
    margin-bottom: 1.25rem;
    color: #3a7afe;
}

.selected-text {
    padding: 12px;
    background: #f7f8fa;
    border-radius: 6px;
    margin-bottom: 15px;
    font-size: 16px;
    min-height: 50px;
    word-break: break-all;
    -webkit-user-select: text;
    user-select: text;
}

.action-buttons {
    display: flex;
    gap: 12px;
}

.instructions {
    margin-top: 30px;
    padding: 15px;
    background: #e8f4ff;
    border-radius: 8px;
    font-size: 14px;
}

.instructions h3 {
    margin-bottom: 10px;
    color: #1989fa;
}

.instructions ul {
    padding-left: 20px;
}

.instructions li {
    margin-bottom: 8px;
}

.selected-item {
    padding: 8px;
    margin-bottom: 8px;
    background: #f0f0f0;
    border-radius: 4px;
    border-left: 3px solid #E95294;
}
</style>

<style>
/* 全局样式 */
.selection-handle {
    position: absolute;
    width: 24px;
    height: 24px;
    background: #07c160;
    border-radius: 50%;
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: bold;
    cursor: move;
    touch-action: none;
    z-index: 1000;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    pointer-events: auto;
    transform: translate(-50%, -50%);
    transition: transform 0.1s ease;
    will-change: transform;
}

.selection-handle:active {
    transform: translate(-50%, -50%) scale(1.1);
}

/* 当手柄接近边界时的视觉反馈 */
.selection-handle.at-boundary {
    background: #ff9700;
}

.selection-handle-start {
    background: #07c160;
}

.selection-handle-end {
    background: #07c160;
}

/* 修改工具栏样式，相对于末端手柄定位 */
.custom-selection-toolbar {
    position: absolute;
    z-index: 1009;
    min-width: 150px;
    /* 默认样式，当作为独立元素时使用 */
    bottom: 40px;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
    /* 防止按钮换行 */
    pointer-events: auto;
    /* 确保工具栏可以接收事件 */
}

/* 添加响应式处理 */
@media (max-width: 400px) {
    .custom-selection-toolbar {
        min-width: 120px;
        font-size: 12px;
    }

    .toolbar-btn {
        padding: 6px 12px;
        font-size: 12px;
    }
}

.toolbar-btn {
    padding: 6px 16px;
    border: none;
    border-radius: 16px;
    font-size: 1rem;
    font-weight: 500;
    cursor: pointer;
    /* 确保按钮有点击光标 */
    pointer-events: auto;
    /* 确保按钮可以接收事件 */
    user-select: none;
    /* 防止按钮文本被选中 */
}

.cancel-btn {
    background: #f0f0f0;
    color: #333;
}

.submit-btn {
    background: #07c160;
    color: white;
}

/* 文本选择样式 */
::selection {
    background: rgba(7, 193, 96, 0.2);
}

.text-highlight {
    background-color: rgba(233, 82, 148, 0.1) !important;
    text-decoration: underline !important;
    text-decoration-color: #E95294 !important;
    text-decoration-thickness: 2px !important;
}
</style>